home *** CD-ROM | disk | FTP | other *** search
/ Network PC / Network PC.iso / amiga utilities / communication / internet / amitcp3.0b / src.lha / src / devtools / cpp / cpp4.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-08  |  19.7 KB  |  703 lines

  1. /*
  2.  *                C P P 4 . C
  3.  *        M a c r o  D e f i n i t i o n s
  4.  *
  5.  * Edit History
  6.  * 31-Aug-84    MM    USENET net.sources release
  7.  * 04-Oct-84    MM    __LINE__ and __FILE__ must call ungetstring()
  8.  *            so they work correctly with token concatenation.
  9.  *            Added string formal recognition.
  10.  * 25-Oct-84    MM    "Short-circuit" evaluate #if's so that we
  11.  *            don't print unnecessary error messages for
  12.  *            #if !defined(FOO) && FOO != 0 && 10 / FOO ...
  13.  * 31-Oct-84    ado/MM    Added token concatenation
  14.  *  6-Nov-84    MM    Split off eval stuff
  15.  * 21-Oct-85    RMS    Rename `token' to `tokenbuf'.
  16.  *            In doundef, don't complain if arg already not defined.
  17.  * 14-Mar-86    FNF    Incorporate macro based C debugging package.
  18.  *            Port to Commodore AMIGA.
  19.  * 21-Aug-88    Ois    Changed concatenation operator to ##. Changed hand-
  20.  *            ling of tokens following ##. Added new meaning of #.
  21.  */
  22.  
  23. #include    <stdio.h>
  24. #include    <ctype.h>
  25. #include    "cppdef.h"
  26. #include    "cpp.h"
  27.  
  28. #ifdef __STDC__
  29. void dodefine(void);
  30. void textput(char *text);
  31. void checkparm(register int c, DEFBUF *dp, int quoting);
  32. #if STRING_FORMAL
  33. void stparmscan(int delim, register DEFBUF *dp);
  34. #else
  35. void stparmscan(int delim);
  36. #endif
  37. void doundef(void);
  38. void charput(register int c);
  39. void expand(register DEFBUF *tokenp);
  40. FILE_LOCAL int expcollect(void);
  41. FILE_LOCAL void expstuff(DEFBUF *tokenp);
  42. FILE_LOCAL char *doquoting(register char *to, register char *from);
  43. #endif
  44.  
  45. /*
  46.  * parm[], parmp, and parlist[] are used to store #define() argument
  47.  * lists.  nargs contains the actual number of parameters stored.
  48.  */
  49. static char    parm[NPARMWORK + 1];    /* define param work buffer    */
  50. static char    *parmp;         /* Free space in parm        */
  51. static char    *parlist[LASTPARM];    /* -> start of each parameter    */
  52. static int    nargs;            /* Parameters for this macro    */
  53.  
  54. void
  55. dodefine()
  56. /*
  57.  * Called from control when a #define is scanned.  This module
  58.  * parses formal parameters and the replacement string.  When
  59.  * the formal parameter name is encountered in the replacement
  60.  * string, it is replaced by a character in the range 128 to
  61.  * 128+NPARAM (this allows up to 32 parameters within the
  62.  * Dec Multinational range).  If cpp is ported to an EBCDIC
  63.  * machine, you will have to make other arrangements.
  64.  *
  65.  * There is some special case code to distinguish
  66.  *    #define foo    bar
  67.  * from #define foo()   bar
  68.  *
  69.  * Also, we make sure that
  70.  *    #define foo    foo
  71.  * expands to "foo" but doesn't put cpp into an infinite loop.
  72.  *
  73.  * A warning message is printed if you redefine a symbol to a
  74.  * different text.  I.e,
  75.  *    #define foo    123
  76.  *    #define foo    123
  77.  * is ok, but
  78.  *    #define foo    123
  79.  *    #define foo    +123
  80.  * is not.
  81.  *
  82.  * The following subroutines are called from define():
  83.  * checkparm    called when a token is scanned.  It checks through the
  84.  *        array of formal parameters.  If a match is found, the
  85.  *        token is replaced by a control byte which will be used
  86.  *        to locate the parameter when the macro is expanded.
  87.  * textput    puts a string in the macro work area (parm[]), updating
  88.  *        parmp to point to the first free byte in parm[].
  89.  *        textput() tests for work buffer overflow.
  90.  * charput    puts a single character in the macro work area (parm[])
  91.  *        in a manner analogous to textput().
  92.  */
  93. {
  94.     register int        c;
  95.     register DEFBUF     *dp;        /* -> new definition    */
  96.     int            isredefine;    /* TRUE if redefined    */
  97.     char            *old;        /* Remember redefined    */
  98. #if OK_CONCAT
  99.     register int        quoting;    /* Remember we saw a #    */
  100. #endif
  101.     extern void        save();         /* Save char in work[]  */
  102.  
  103.     DBUG_ENTER ("dodefine");
  104.     if (type[(c = skipws())] != LET)
  105.         goto bad_define;
  106.     isredefine = FALSE;            /* Set if redefining    */
  107.     if ((dp = lookid(c)) == NULL)           /* If not known now     */
  108.         dp = defendel(tokenbuf, FALSE);     /* Save the name        */
  109.     else {                    /* It's known:          */
  110.         isredefine = TRUE;            /* Remember this fact    */
  111.         old = dp->repl;            /* Remember replacement */
  112.         dp->repl = NULL;            /* No replacement now    */
  113.     }
  114.     parlist[0] = parmp = parm;        /* Setup parm buffer    */
  115.     if ((c = get()) == '(') {               /* With arguments?      */
  116.         nargs = 0;                /* Init formals counter */
  117.         do {                /* Collect formal parms */
  118.         if (nargs >= LASTPARM)
  119.             cfatal("Too many arguments for macro", NULLST);
  120.         else if ((c = skipws()) == ')')
  121.             break;            /* Got them all     */
  122.         else if (type[c] != LET)        /* Bad formal syntax    */
  123.             goto bad_define;
  124.         scanid(c);                      /* Get the formal param */
  125.         parlist[nargs++] = parmp;    /* Save its start    */
  126.         textput(tokenbuf);              /* Save text in parm[]  */
  127.         } while ((c = skipws()) == ',');    /* Get another argument */
  128.         if (c != ')')                       /* Must end at )        */
  129.         goto bad_define;
  130.         c = ' ';                            /* Will skip to body    */
  131.     }
  132.     else {
  133.         /*
  134.          * DEF_NOARGS is needed to distinguish between
  135.          * "#define foo" and "#define foo()".
  136.          */
  137.         nargs = DEF_NOARGS;         /* No () parameters     */
  138.     }
  139.     if (type[c] == SPA)                     /* At whitespace?       */
  140.         c = skipws();                       /* Not any more.        */
  141.     workp = work;                /* Replacement put here */
  142.     inmacro = TRUE;             /* Keep \<newline> now    */
  143.     quoting = 0;                /* No # seen yet.    */
  144.     while (c != EOF_CHAR && c != '\n') {    /* Compile macro body   */
  145. #if OK_CONCAT
  146.         if (c == '#') {                     /* Token concatenation? */
  147.         if ((c = get()) != '#') {       /* No, not really       */
  148.             quoting = 1;        /* Maybe quoting op.    */
  149.             continue;
  150.         }
  151.         while (workp > work && type[workp[-1]] == SPA)
  152.             --workp;            /* Erase leading spaces */
  153.         save(TOK_SEP);                  /* Stuff a delimiter    */
  154.         c = skipws();                   /* Eat whitespace       */
  155. #if 0
  156.         if (type[c] == LET)             /* Another token here?  */
  157.             ;                /* Stuff it normally    */
  158.         else if (type[c] == DIG) {      /* Digit string after?  */
  159.             while (type[c] == DIG) {    /* Stuff the digits     */
  160.             save(c);                /* Note
  161.             c = get();
  162.             }
  163.             save(TOK_SEP);              /* Delimit 2nd token    */
  164.         }
  165.         else {
  166.             ciwarn("Strange character after ## (%d.)", c);
  167.         }
  168. #endif
  169.         continue;
  170.         }
  171. #endif
  172.         switch (type[c]) {
  173.         case LET:
  174. #if OK_CONCAT
  175.         checkparm(c, dp, quoting);      /* Might be a formal    */
  176. #else
  177.         checkparm(c, dp);               /* Might be a formal    */
  178. #endif
  179.         break;
  180.  
  181.         case DIG:                /* Number in mac. body    */
  182.         case DOT:                /* Maybe a float number */
  183.         scannumber(c, save);            /* Scan it off          */
  184.         break;
  185.  
  186.         case QUO:                /* String in mac. body    */
  187. #if STRING_FORMAL
  188.         stparmscan(c, dp);              /* Do string magic      */
  189. #else
  190.         stparmscan(c);
  191. #endif
  192.         break;
  193.  
  194.         case BSH:                /* Backslash        */
  195.         save('\\');
  196.         if ((c = get()) == '\n')
  197.             wrongline = TRUE;
  198.         save(c);
  199.         break;
  200.  
  201.         case SPA:                /* Absorb whitespace    */
  202.         /*
  203.          * Note: the "end of comment" marker is passed on
  204.          * to allow comments to separate tokens.
  205.          */
  206.         if (workp[-1] == ' ')           /* Absorb multiple      */
  207.             break;            /* spaces        */
  208.         else if (c == '\t')
  209.             c = ' ';                    /* Normalize tabs       */
  210.         /* Fall through to store character            */
  211.         default:                /* Other character    */
  212.         save(c);
  213.         break;
  214.         }
  215.         c = get();
  216.         quoting = 0;            /* Only when immediately*/
  217.                         /* preceding a formal    */
  218.     }
  219.     inmacro = FALSE;            /* Stop newline hack    */
  220.     unget();                                /* For control check    */
  221.     if (workp > work && workp[-1] == ' ')   /* Drop trailing blank  */
  222.         workp--;
  223.     *workp = EOS;                /* Terminate work    */
  224.     dp->repl = savestring(work);            /* Save the string      */
  225.     dp->nargs = nargs;            /* Save arg count    */
  226. #if DEBUG
  227.     if (debug)
  228.         dumpadef("macro definition", dp);
  229. #endif
  230.     if (isredefine) {                       /* Error if redefined   */
  231.         if ((old != NULL && dp->repl != NULL && !streq(old, dp->repl))
  232.          || (old == NULL && dp->repl != NULL)
  233.          || (old != NULL && dp->repl == NULL)) {
  234.         cerror("Redefining defined variable \"%s\"", dp->name);
  235.         }
  236.         if (old != NULL)                    /* We don't need the    */
  237.         free(old);                      /* old definition now.  */
  238.     }
  239.     DBUG_VOID_RETURN;
  240.  
  241. bad_define:
  242.     cerror("#define syntax error", NULLST);
  243.     inmacro = FALSE;            /* Stop <newline> hack    */
  244.     DBUG_VOID_RETURN;
  245. }
  246.  
  247. void
  248. checkparm(c, dp, quoting)
  249. register int    c;
  250. DEFBUF        *dp;
  251. int        quoting;            /* Preceded by a # ?    */
  252. /*
  253.  * Replace this param if it's defined.  Note that the macro name is a
  254.  * possible replacement token.    We stuff DEF_MAGIC in front of the token
  255.  * which is treated as a LETTER by the token scanner and eaten by
  256.  * the output routine.    This prevents the macro expander from
  257.  * looping if someone writes "#define foo foo".
  258.  */
  259. {
  260.     register int        i;
  261.     register char        *cp;
  262.  
  263.     DBUG_ENTER ("checkparm");
  264.     scanid(c);                              /* Get parm to tokenbuf */
  265.     for (i = 0; i < nargs; i++) {           /* For each argument    */
  266.         if (streq(parlist[i], tokenbuf)) {  /* If it's known        */
  267. #if OK_CONCAT
  268.         if (quoting)                    /* Special handling of  */
  269.             save(QUOTE_PARM);           /* #formal inside defn  */
  270. #endif
  271.         save(i + MAC_PARM);             /* Save a magic cookie  */
  272.         DBUG_VOID_RETURN;        /* And exit the search    */
  273.         }
  274.     }
  275.     if (streq(dp->name, tokenbuf))          /* Macro name in body?  */
  276.         save(DEF_MAGIC);                    /* Save magic marker    */
  277.     for (cp = tokenbuf; *cp != EOS;)        /* And save             */
  278.         save(*cp++);                        /* The token itself     */
  279.     DBUG_VOID_RETURN;
  280. }
  281.  
  282. #if STRING_FORMAL
  283. void
  284. stparmscan(delim, dp)
  285. int        delim;
  286. register DEFBUF *dp;
  287. /*
  288.  * Scan the string (starting with the given delimiter).
  289.  * The token is replaced if it is the only text in this string or
  290.  * character constant.    The algorithm follows checkparm() above.
  291.  * Note that scanstring() has approved of the string.
  292.  */
  293. {
  294.     register int        c;
  295.  
  296.     DBUG_ENTER ("stparmscan");
  297.     /*
  298.      * Warning -- this code hasn't been tested for a while.
  299.      * It exists only to preserve compatibility with earlier
  300.      * implementations of cpp.  It is not part of the Draft
  301.      * ANSI Standard C language.
  302.      */
  303.     save(delim);
  304.     instring = TRUE;
  305.     while ((c = get()) != delim
  306.          && c != '\n'
  307.          && c != EOF_CHAR) {
  308.         if (type[c] == LET)                 /* Maybe formal parm    */
  309.         checkparm(c, dp, 0);
  310.         else {
  311.         save(c);
  312.         if (c == '\\')
  313.             save(get());
  314.         }
  315.     }
  316.     instring = FALSE;
  317.     if (c != delim)
  318.         cerror("Unterminated string in macro body", NULLST);
  319.     save(c);
  320.     DBUG_VOID_RETURN;
  321. }
  322. #else
  323. void
  324. stparmscan(delim)
  325. int        delim;
  326. /*
  327.  * Normal string parameter scan.
  328.  */
  329. {
  330.     register char        *wp;
  331.     register int        i;
  332.     extern void        save();
  333.  
  334.     DBUG_ENTER ("stparmscan");
  335.     wp = workp;            /* Here's where it starts       */
  336.     if (!scanstring(delim, save))
  337.         DBUG_VOID_RETURN;        /* Exit on scanstring error    */
  338.     workp[-1] = EOS;        /* Erase trailing quote     */
  339.     wp++;                /* -> first string content byte */
  340.     for (i = 0; i < nargs; i++) {
  341.         if (streq(parlist[i], wp)) {
  342.         *wp++ = MAC_PARM + PAR_MAC;    /* Stuff a magic marker */
  343.         *wp++ = (i + MAC_PARM);         /* Make a formal marker */
  344.         *wp = wp[-3];            /* Add on closing quote */
  345.         workp = wp + 1;         /* Reset string end    */
  346.         DBUG_VOID_RETURN;
  347.         }
  348.     }
  349.     workp[-1] = wp[-1];        /* Nope, reset end quote.    */
  350.     DBUG_VOID_RETURN;
  351. }
  352. #endif
  353.  
  354. void
  355. doundef()
  356. /*
  357.  * Remove the symbol from the defined list.
  358.  * Called from the #control processor.
  359.  */
  360. {
  361.   register int c;
  362.  
  363.   DBUG_ENTER ("doundef");
  364.   if (type[(c = skipws())] != LET)
  365.     cerror("Illegal #undef argument", NULLST);
  366.   else
  367.     {
  368.       scanid(c);                                /* Get name to tokenbuf */
  369.       (void) defendel(tokenbuf, TRUE);
  370.     }
  371.   DBUG_VOID_RETURN;
  372. }
  373.  
  374. void
  375. textput(text)
  376. char        *text;
  377. /*
  378.  * Put the string in the parm[] buffer.
  379.  */
  380. {
  381.     register int    size;
  382.  
  383.     DBUG_ENTER ("textput");
  384.     size = strlen(text) + 1;
  385.     if ((parmp + size) >= &parm[NPARMWORK])
  386.         cfatal("Macro work area overflow", NULLST);
  387.     else {
  388.         strcpy(parmp, text);
  389.         parmp += size;
  390.     }
  391.     DBUG_VOID_RETURN;
  392. }
  393.  
  394. void
  395. charput(c)
  396. register int    c;
  397. /*
  398.  * Put the byte in the parm[] buffer.
  399.  */
  400. {
  401.     if (parmp >= &parm[NPARMWORK])
  402.         cfatal("Macro work area overflow", NULLST);
  403.     else {
  404.         *parmp++ = c;
  405.     }
  406. }
  407.  
  408. /*
  409.  *        M a c r o   E x p a n s i o n
  410.  */
  411.  
  412. static DEFBUF    *macro;     /* Catches start of infinite macro    */
  413.  
  414. void
  415. expand(tokenp)
  416. register DEFBUF *tokenp;
  417. /*
  418.  * Expand a macro.  Called from the cpp mainline routine (via subroutine
  419.  * macroid()) when a token is found in the symbol table.  It calls
  420.  * expcollect() to parse actual parameters, checking for the correct number.
  421.  * It then creates a "file" containing a single line containing the
  422.  * macro with actual parameters inserted appropriately.  This is
  423.  * "pushed back" onto the input stream.  (When the get() routine runs
  424.  * off the end of the macro line, it will dismiss the macro itself.)
  425.  */
  426. {
  427.     register int        c;
  428.     register FILEINFO    *file;
  429.     extern FILEINFO     *getfile();
  430.  
  431.     DBUG_ENTER ("expand");
  432. #if DEBUG
  433.     if (debug)
  434.         dumpadef("expand entry", tokenp);
  435. #endif
  436.     /*
  437.      * If no macro is pending, save the name of this macro
  438.      * for an eventual error message.
  439.      */
  440.     if (recursion++ == 0)
  441.         macro = tokenp;
  442.     else if (recursion == RECURSION_LIMIT) {
  443.         cerror("Recursive macro definition of \"%s\"", tokenp->name);
  444.         fprintf(stderr, "(Defined by \"%s\")\n", macro->name);
  445.         if (rec_recover) {
  446.         do {
  447.             c = get();
  448.         } while (infile != NULL && infile->fp == NULL);
  449.         unget();
  450.         recursion = 0;
  451.         DBUG_VOID_RETURN;
  452.         }
  453.     }
  454.     /*
  455.      * Here's a macro to expand.
  456.      */
  457.     nargs = 0;                /* Formals counter    */
  458.     parmp = parm;                /* Setup parm buffer    */
  459.     switch (tokenp->nargs) {
  460.     case (-2):                              /* __LINE__             */
  461.         sprintf(work, "%d", line);
  462.         ungetstring(work);
  463.         break;
  464.  
  465.     case (-3):                              /* __FILE__             */
  466.         for (file = infile; file != NULL; file = file->parent) {
  467.         if (file->fp != NULL) {
  468.             sprintf(work, "\"%s\"", (file->progname != NULL)
  469.             ? file->progname : file->filename);
  470.             ungetstring(work);
  471.             break;
  472.         }
  473.         }
  474.         break;
  475.  
  476.     default:
  477.         /*
  478.          * Nothing funny about this macro.
  479.          */
  480.         if (tokenp->nargs < 0)
  481.         cfatal("Bug: Illegal __ macro \"%s\"", tokenp->name);
  482.         while ((c = skipws()) == '\n')      /* Look for (, skipping */
  483.         wrongline = TRUE;        /* spaces and newlines    */
  484.         if (c != '(') {
  485.         /*
  486.          * If the programmer writes
  487.          *    #define foo() ...
  488.          *    ...
  489.          *    foo [no ()]
  490.          * just write foo to the output stream.
  491.          */
  492.         unget();
  493.         cwarn("Macro \"%s\" needs arguments", tokenp->name);
  494.         fputs(tokenp->name, stdout);
  495.         DBUG_VOID_RETURN;
  496.         }
  497.         else if (expcollect()) {            /* Collect arguments    */
  498.         if (tokenp->nargs != nargs) {   /* Should be an error?  */
  499.             cwarn("Wrong number of macro arguments for \"%s\"",
  500.             tokenp->name);
  501.         }
  502. #if DEBUG
  503.         if (debug)
  504.             dumpparm("expand");
  505. #endif
  506.         }                /* Collect arguments        */
  507.     case DEF_NOARGS:        /* No parameters just stuffs    */
  508.         expstuff(tokenp);           /* Do actual parameters         */
  509.     }                /* nargs switch         */
  510.     DBUG_VOID_RETURN;
  511. }
  512.  
  513. FILE_LOCAL int
  514. expcollect()
  515. /*
  516.  * Collect the actual parameters for this macro.  TRUE if ok.
  517.  */
  518. {
  519.     register int    c;
  520.     register int    paren;            /* For embedded ()'s    */
  521.     extern void    charput();
  522.  
  523.     DBUG_ENTER ("expcollect");
  524.     for (;;) {
  525.         paren = 0;                /* Collect next arg.    */
  526.         while ((c = skipws()) == '\n')      /* Skip over whitespace */
  527.         wrongline = TRUE;        /* and newlines.    */
  528.         if (c == ')') {                     /* At end of all args?  */
  529.         /*
  530.          * Note that there is a guard byte in parm[]
  531.          * so we don't have to check for overflow here.
  532.          */
  533.         *parmp = EOS;            /* Make sure terminated */
  534.         break;                /* Exit collection loop */
  535.         }
  536.         else if (nargs >= LASTPARM)
  537.         cfatal("Too many arguments in macro expansion", NULLST);
  538.         parlist[nargs++] = parmp;        /* At start of new arg    */
  539.         for (;; c = cget()) {               /* Collect arg's bytes  */
  540.         if (c == EOF_CHAR) {
  541.             cerror("end of file within macro argument", NULLST);
  542.             DBUG_RETURN (FALSE);                /* Sorry.               */
  543.         }
  544.         else if (c == '\\') {           /* Quote next character */
  545.             charput(c);                 /* Save the \ for later */
  546.             charput(cget());            /* Save the next char.  */
  547.             continue;            /* And go get another    */
  548.         }
  549.         else if (type[c] == QUO) {      /* Start of string?     */
  550.             scanstring(c, charput);     /* Scan it off          */
  551.             continue;            /* Go get next char    */
  552.         }
  553.         else if (c == '(')              /* Worry about balance  */
  554.             paren++;            /* To know about commas */
  555.         else if (c == ')') {            /* Other side too       */
  556.             if (paren == 0) {           /* At the end?          */
  557.             unget();                /* Look at it later     */
  558.             break;            /* Exit arg getter.    */
  559.             }
  560.             paren--;            /* More to come.    */
  561.         }
  562.         else if (c == ',' && paren == 0) /* Comma delimits args */
  563.             break;
  564.         else if (c == '\n')             /* Newline inside arg?  */
  565.             wrongline = TRUE;        /* We'll need a #line   */
  566.         charput(c);                     /* Store this one       */
  567.         }                    /* Collect an argument    */
  568.         charput(EOS);                       /* Terminate argument   */
  569. #if DEBUG
  570.         if (debug)
  571.         printf("parm[%d] = \"%s\"\n", nargs, parlist[nargs - 1]);
  572. #endif
  573.     }                    /* Collect all args.    */
  574.     DBUG_RETURN (TRUE);                     /* Normal return        */
  575. }
  576.  
  577.  
  578. #if OK_CONCAT
  579.  
  580. FILE_LOCAL
  581. char *doquoting(to, from)
  582. register char *to;
  583. register char *from;
  584. {
  585.     *to++ = '"';
  586.     while (*from) {
  587.     if (*from == '\\' || *from == '"')
  588.         *to++ = '\\';
  589.     *to++ = *from++;
  590.     }
  591.     *to++ = '"';
  592.  
  593.     return to;
  594. }
  595.  
  596. #endif
  597.  
  598. FILE_LOCAL void
  599. expstuff(tokenp)
  600. DEFBUF        *tokenp;        /* Current macro being expanded */
  601. /*
  602.  * Stuff the macro body, replacing formal parameters by actual parameters.
  603.  */
  604. {
  605.     register int    c;            /* Current character    */
  606.     register char    *inp;            /* -> repl string    */
  607.     register char    *defp;            /* -> macro output buff */
  608.     int        size;            /* Actual parm. size    */
  609.     char        *defend;        /* -> output buff end    */
  610.     int        string_magic;        /* String formal hack    */
  611.     FILEINFO    *file;            /* Funny #include    */
  612. #if OK_CONCAT
  613.     register char         quoting;    /* Quote macro argument */
  614. #endif
  615.     extern FILEINFO *getfile();
  616.  
  617.     DBUG_ENTER ("expstuff");
  618.     file = getfile(NBUFF, tokenp->name);
  619.     inp = tokenp->repl;            /* -> macro replacement */
  620.     defp = file->buffer;            /* -> output buffer    */
  621.     defend = defp + (NBUFF - 1);            /* Note its end         */
  622.     if (inp != NULL) {
  623.         quoting = 0;
  624.         while ((c = (*inp++ & 0xFF)) != EOS) {
  625. #if OK_CONCAT
  626.         if (c == QUOTE_PARM) {          /* Special token for #  */
  627.             quoting = 1;        /* set flag, for later    */
  628.             continue;            /* Get next character    */
  629.         }
  630. #endif
  631.         if (c >= MAC_PARM && c <= (MAC_PARM + PAR_MAC)) {
  632.             string_magic = (c == (MAC_PARM + PAR_MAC));
  633.             if (string_magic)
  634.             c = (*inp++ & 0xFF);
  635.             /*
  636.              * Replace formal parameter by actual parameter string.
  637.              */
  638.             if ((c -= MAC_PARM) < nargs) {
  639.             size = strlen(parlist[c]);
  640. #if OK_CONCAT
  641.             if (quoting) {
  642.                 size++;
  643.                 size *= 2;        /* worst case condition */
  644.             }
  645. #endif
  646.             if ((defp + size) >= defend)
  647.                 goto nospace;
  648.             /*
  649.              * Erase the extra set of quotes.
  650.              */
  651.             if (string_magic && defp[-1] == parlist[c][0]) {
  652.                 strcpy(defp-1, parlist[c]);
  653.                 defp += (size - 2);
  654.             }
  655. #if OK_CONCAT
  656.             else if (quoting)
  657.                 defp = doquoting(defp, parlist[c]);
  658. #endif
  659.             else {
  660.                 strcpy(defp, parlist[c]);
  661.                 defp += size;
  662.             }
  663.             }
  664.         }
  665.         else if (defp >= defend) {
  666. nospace:        cfatal("Out of space in macro \"%s\" arg expansion",
  667.             tokenp->name);
  668.         }
  669.         else {
  670.             *defp++ = c;
  671.         }
  672.         quoting = 0;
  673.         }
  674.     }
  675.     *defp = EOS;
  676. #if DEBUG
  677.     if (debug > 1)
  678.         printf("macroline: \"%s\"\n", file->buffer);
  679. #endif
  680.     DBUG_VOID_RETURN;
  681. }
  682.  
  683. #if DEBUG
  684. void
  685. dumpparm(why)
  686. char        *why;
  687. /*
  688.  * Dump parameter list.
  689.  */
  690. {
  691.     register int    i;
  692.  
  693.     DBUG_ENTER ("dumpparm");
  694.     printf("dump of %d parameters (%d bytes total) %s\n",
  695.         nargs, parmp - parm, why);
  696.     for (i = 0; i < nargs; i++) {
  697.         printf("parm[%d] (%d) = \"%s\"\n",
  698.         i + 1, strlen(parlist[i]), parlist[i]);
  699.     }
  700.     DBUG_VOID_RETURN;
  701. }
  702. #endif
  703.